/*
 * Creates sockets for multithreading
 * Licensed by the Bunie Developmentgroup.
 */

package infoserver;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.logging.Logger;

/**
 * @author Patrick Wobben
 * @since 3-5-2012
 * @version v0.95
 */

public class SocketFactory {

    private ArrayList<Socket> listOfClients = new ArrayList<Socket>();
    private Socket client = null;
    private int numConnections = 0;
    private final static Logger LOGGER = Logger.getLogger(Log.class.getName());

    /**
     * Constructor for the SocketFactory
     * Creates a new thread for every new connection.
     * @author Patrick Wobben
     * @version v0.95
     * @since v0.95
     * @param listenPort Need the created ServerSocket for accepting connection.
     */
    
    public SocketFactory(ServerSocket listenPort){
        SocketConnection newConnection = null;
            while(true){
                try {
                    client = listenPort.accept();
                    numConnections++;
                    newConnection = new SocketConnection(client,numConnections);
                    listOfClients.add(client);
					connectionsNumber();
                    printArraylist();
                    new Thread(newConnection).start();
                } catch (IOException e) {
                    Log.print("Error: " + e, Log.SEVERE);
                }
                                
                
            }
    }
    
    public void printArraylist (){
        Object[] elements = listOfClients.toArray();
        Log.print("List of connected sockets", Log.INFO);
        
        for (int a = 0; a< elements.length; a++){
            Log.print("Socket: " + elements[a],Log.INFO);
        }
    }
	
	private void connectionsNumber(){
		if (numConnections > 1){
			for (int i=0; i<numConnections; i++) {
						if (listOfClients.get(i).isClosed()) {
							listOfClients.remove(i);
							numConnections--;
						} 

						if(listOfClients.get(i) == null){
							listOfClients.remove(i);
							numConnections--;
						}
			}
		}
	}
    /**
     * Method to get the client who's connected to the Factory
     * @author Patrick Wobben
     * @since v0.9
     * @version v0.9
     * @return the connected socket.
     */
    public ArrayList<Socket> getConnectedSocket(){
        return listOfClients;
    }
    
    /**
     * Method to set the amount of connections (different clients)
     * @author Patrick Wobben
     * @since v0.9
     * @version v0.9
     * @param number 
     */
    public void setConnections(int number ){
        this.numConnections = numConnections + number;
    }
    
    /**
     * Class for new connection and thread.
     * @author Patrick Wobben
     * @since: v0.95
     * @version: v0.95
     */
   
    class SocketConnection implements Runnable {
       
        BufferedReader is;
        PrintStream os;
        Socket client;
        int id;
        
        /**
         * Constructor for class. Creates connection (reader/writer).
         * @author: Patrick Wobben
         * @since: v0.95
         * @version: v0.95
         */
        public SocketConnection (Socket client, int number){
            this.client = client;
            this.id = number;
            Log.print( "Connection " + id + " established with: " + client, Log.INFO );
            try {
                is = new BufferedReader(new InputStreamReader(client.getInputStream()));
                os = new PrintStream(client.getOutputStream());
            } catch (IOException e) {
                Log.print("Error: " + e, Log.SEVERE);
            }
        }
        
        
        /**
         * Method that overrides Run in 'Runnable'. 
         * Creates new ServerProcessor after new thread is started.
         * @author: Patrick Wobben
         * @version: v0.95
         * @since: v0.95
         */
        @Override
        public void run(){
                Thread t = Thread.currentThread();
                Log.print("Current thread: " + t, Log.INFO);
                int active  = Thread.activeCount();
                Log.print("Number of active threads: " + active, Log.INFO);
                new ServerProcessor(client,SocketFactory.this);
        }
        
       
    }
}
